#! /usr/bin/env python
# -*- coding: utf8 -*-

import cElementTree as et

import errno
import fuse
import stat
import sys
import os
import re

def tPath(path, root):
    rt = re.compile("\[[0-9]+\]$")
    t  = root # current "root"
    
    for i in path.split('/'):
        if i == '':
            if type(t) == list or t.getchildren():
                continue
            return None # trying to access an element as a dir.
        
        m = rt.search(i)
        if m != None:
            tp = i[:m.start()]
            tn = int(i[m.start() + 1:-1])
            
            t = t.findall(tp)
            if tn < 0 or tn > len(t) or len(t) <= 1:
                return None

            t = t[tn]
        else:
            print i
            t = t.findall(i)
            if len(t) == 1:
                return t[0]
                
            if len(t) == 0:
                return None
    return t    

class XFstat(fuse.Stat):
    def __init__(self):
        self.st_mode = 0
        self.st_ino = 0
        self.st_dev = 0
        self.st_nlink = 0
        self.st_uid = 0
        self.st_gid = 0
        self.st_size = 0
        self.st_atime = 0
        self.st_mtime = 0
        self.st_ctime = 0

class XMLfuse(fuse.Fuse):
    def main(self, *a, **kw):
        if not hasattr(self, "xmlfile"):
            print "Unable to proceed. -o xmlfile=<path to XML file> is required!"
            sys.exit(1)
        
        self.__tree = et.parse(self.xmlfile).getroot()
        return fuse.Fuse.main(self, *a, **kw)

    # File operation methods.
    def getattr(self, path):
        st = XFstat()
        fp = tPath(path, self.__tree)
        
        if path.replace("/", '') == "":
            fp = fp.getchildren()
        
        if type(fp) == list or len(fp.getchildren()) > 0:
            st.st_mode = stat.S_IFDIR | 0755
            st.st_nlink = 2
        elif len(fp.getchildren()) == 0:
            st.st_mode = stat.S_IFREG | 0444
            st.st_nlink = 1
            
            if fp.text != None:
                st.st_size = len(fp.text)
        else:
            return -errno.ENOENT
        
        return st
        
    def open(self, path, flags):
        fp = tPath(path, self.__tree)
        
        if type(fp) in [list, type(None)]:
            return -errno.ENOENT
        
        accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
        if (flags & accmode) != os.O_RDONLY:
            return -errno.EACCES
        
    def readdir(self, path, offset):
        node = tPath(path, self.__tree)
        chil = node.getchildren()
        tags = []
        
        for x in chil:
            if x.tag not in tags:
                tags.append(x.tag)
        
        for i in ['.', '..']:
            yield fuse.Direntry(i)
        
        for i in tags:
            res = node.findall(i)
            if len(res) == 1:
                yield fuse.Direntry(i)
            else:
                for j in range(len(res)):
                    yield fuse.Direntry("%s[%d]" % (i, j))
        
    def read(self, path, size, offset):
        fp = tPath(path, self.__tree)
        
        if type(fp) == list or fp == None:
            return -errno.ENOENT
            
        return fp.text[offset:size + offset]
        
server = XMLfuse()
server.parser.add_option(mountopt="xmlfile", metavar="PATH", help="blaat")
server.parse(values=server, errex=1)
server.main()